package tools;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONException;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.util.*;

import static org.apache.commons.lang3.StringUtils.isNotBlank;

@Slf4j
public class LiporUtils {


    public static <T> T jsonToObject(String objStr, Class<T> c) {
        if (objStr != null && !"".equals(objStr)) {
            try {
                ObjectMapper objectMapper = new ObjectMapper();
                return objectMapper.readValue(objStr, c);
            } catch (Exception var3) {
                log.error("jsonToObject-fail-1, objStr: {}", objStr);
                var3.printStackTrace();
                return null;
            }
        } else {
            return null;
        }
    }

    public static <T> T jsonToObject(String objStr, com.fasterxml.jackson.core.type.TypeReference c) {
        if (objStr != null && !"".equals(objStr)) {
            try {
                ObjectMapper objectMapper = new ObjectMapper();
                return objectMapper.readValue(objStr, c);
            } catch (Exception var3) {
                log.error("jsonToObject-fail-2, objStr: {}", objStr);
                var3.printStackTrace();
                return null;
            }
        } else {
            return null;
        }
    }

    public static <T> List<T> jsonToList(String objStr, Class<T> c) {
        if (objStr != null && !"".equals(objStr)) {
            try {
                List<T> list;
                ObjectMapper mapper = new ObjectMapper();
                mapper.configure(JsonParser.Feature.ALLOW_UNQUOTED_FIELD_NAMES, true);
                JavaType javaType = mapper.getTypeFactory().constructParametricType(List.class, c);
                list = mapper.readValue(objStr, javaType);
                return list;
            } catch (Exception var3) {
                log.error("jsonToList-fail, objStr: {}", objStr);
                var3.printStackTrace();
                return null;
            }
        } else {
            return null;
        }
    }

    public static String objectNonNullToJson(Object o) {
        ObjectMapper mapper = new ObjectMapper();
        // 序列化时候，只序列化非空字段
        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
        try {
            return mapper.writeValueAsString(o);
        } catch (JsonProcessingException e) {
            log.error("objectNonNullToJson-fail, Object: {}", o);
            e.printStackTrace();
            return null;
        }
    }

    public static String objectToJson(Object o) {
        return objectToJson(o, false);
    }

    public static String objectToJson(Object o, boolean escapeNonAscii) {
        StringWriter str = new StringWriter();

        try {
            ObjectMapper objectMapper = new ObjectMapper();
            if (escapeNonAscii) {
                objectMapper.getFactory().configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, true);
            }
            objectMapper.writeValue(str, o);
            return str.toString();
        } catch (Exception var3) {
            log.error("objectToJson-fail, Object: {}", o);
            var3.printStackTrace();
            return null;
        }
    }

    /**
     * make object json
     *
     * @param list
     * @return
     */
    public static JSON makeJson(Object[] list) {
        if (null == list) {
            return null;
        }
        boolean isAllKeyString = true;
        for (int i = 0; i < list.length - 1; i += 2) {
            if (list[i] == null || !(list[i] instanceof String)) {
                isAllKeyString = false;
                break;
            }
        }
        if (list.length % 2 != 0 || !isAllKeyString) {
            JSONArray jsonArray = new JSONArray();
            for (Object item : list) {
                if (item instanceof Object[][]) {
                    item = makeJson((Object[][]) item);
                } else if (item instanceof Object[]) {
                    item = makeJson((Object[]) item);
                }
                jsonArray.add(item);
            }
            return jsonArray;
        }
        JSONObject json = new JSONObject(true);
        for (int i = 0; i < list.length - 1; i += 2) {
            String key = (String) list[i];
            Object value = list[i + 1];
            if (value instanceof Object[][]) {
                value = makeJson((Object[][]) value);
            } else if (value instanceof Object[]) {
                value = makeJson((Object[]) value);
            }
            json.put(key, value);
        }
        return json;
    }

    /**
     * make array json
     *
     * @param list
     * @return
     */
    public static JSON makeJson(Object[][] list) {
        JSONArray json = new JSONArray();
        for (Object[] kv : list) {
            json.add(makeJson(kv));
        }
        return json;
    }

    public static String makeJsonString(String s) {
        return JSONObject.parse(s).toString();
    }

    public static String makeJsonString(Object[] list) {
        return JSONObject.toJSONString(makeJson(list), SerializerFeature.WriteMapNullValue);
    }

    public static String makeJsonString(Object[][] list) {
        return JSONObject.toJSONString(makeJson(list), SerializerFeature.WriteMapNullValue);
    }

    public static Map<String, Object> jsonToMap(JSONObject json) throws JSONException {
        Map<String, Object> retMap = new HashMap<String, Object>();
        if (json != null) {
            retMap = toMap(json);
        }
        return retMap;
    }

    /**
     * map to obj
     *
     * @param map
     * @param c
     * @return
     */
    public static <T> T mapToObj(Map<String, String> map, Class<T> c) {
        ObjectMapper mapper = new ObjectMapper();
        return mapper.convertValue(map, c);
    }

    public static Map<String, Object> toMap(JSONObject object) throws JSONException {
        Map<String, Object> map = new HashMap<String, Object>();

        Iterator<String> keysItr = object.keySet().iterator();
        while (keysItr.hasNext()) {
            String key = keysItr.next();
            Object value = object.get(key);

            if (value instanceof JSONArray) {
                value = toList((JSONArray) value);
            } else if (value instanceof JSONObject) {
                value = toMap((JSONObject) value);
            }
            map.put(key, value);
        }
        return map;
    }

    public static List<Object> toList(JSONArray array) throws JSONException {
        List<Object> list = new ArrayList<Object>();
        for (int i = 0; i < array.size(); i++) {
            Object value = array.get(i);
            if (value instanceof JSONArray) {
                value = toList((JSONArray) value);
            } else if (value instanceof JSONObject) {
                value = toMap((JSONObject) value);
            }
            list.add(value);
        }
        return list;
    }


    //计算两时间差,按照标准自然日计算(.年.月.日)
    public static String getDiffDay2(String rentStart, String rentEnd) {
        if (StringUtils.isNotBlank(rentStart) && StringUtils.isNotBlank(rentEnd)) {
            try {
                Date start = DateUtils.stringToDate(rentStart);
                Date end = DateUtils.stringToDate(rentEnd);

                Calendar start1 = Calendar.getInstance();
                start1.setTime(start);

                Calendar end1 = Calendar.getInstance();
                end1.setTime(end);
                int year1 = start1.get(Calendar.YEAR);
                int month1 = start1.get(Calendar.MONTH);
                int day1 = start1.get(Calendar.DAY_OF_MONTH);

                int year2 = end1.get(Calendar.YEAR);
                int month2 = end1.get(Calendar.MONTH);
                int day2 = end1.get(Calendar.DAY_OF_MONTH);

                String str = "";
                int year = (year2 - year1);
                int month = month2 - month1;
                int day = day2 - day1;
                if (day < 0) {
                    //获取日期的最后一天
                    Calendar ca = Calendar.getInstance();
                    ca.setTime(start);
                    ca.set(Calendar.DAY_OF_MONTH, ca.getActualMaximum(Calendar.DAY_OF_MONTH));
                    int lastDay = ca.get(Calendar.DAY_OF_MONTH);
                    day = lastDay - day1 + day2;
                    month--;
                }
                if (month < 0) {
                    //最大月份是11(0-11)
                    month = 11 - month1 + month2;
                    year--;
                }

                if (year > 0) {
                    str = year + "年";
                }
                if (month > 0) {
                    str += month + "个月";
                }
                if (day > 0) {
                    str += day + "天";
                }
                return str;
            } catch (Exception e) {
                log.error("getDiffDay2-fail, rentStart: {}, rentEnd: {}", rentStart, rentEnd);
                return "";
            }
        }
        return "";
    }

    /**
     * 替换掉字符串中的4个字节的字符
     *
     * @param str
     * @return
     */
    public static String replace4ByteStr(String str) {
        //CharUtils.isAscii((char) tt) //1个字节的字符
        //(tt & 0xE0) == 0xC0 //2个字节的字符
        //(tt & 0xF0) == 0xE0 //3个字节的字符
        //(tt & 0xF8) == 0xF0 //4个字节的字符

        String rtn = "";
        if (isNotBlank(str)) {
            byte[] t = str.getBytes(StandardCharsets.UTF_8);
            //获取有效字符的长度
            int len = 0;
            for (int i = 0; i < t.length; ) {
                if ((t[i] & 0xF8) == 0xF0) {
                    //4个字节的字符,开始的第一个字符
                    i += 4;
                } else {
                    //拼接有效的字符
                    i++;
                    len++;
                }
            }

            //拼接byte
            if (len > 0) {
                byte[] bytes = new byte[len];
                for (int i = 0, j = 0; i < t.length; ) {
                    if ((t[i] & 0xF8) == 0xF0) {
                        //4个字节的字符,开始的第一个字符
                        i += 4;
                    } else {
                        //拼接有效的字符
                        bytes[j] = t[i];
                        i++;
                        j++;
                    }
                }
                rtn = new String(bytes, StandardCharsets.UTF_8);
            }
        }
        if (rtn.length() == 0) {
            rtn = "" + System.currentTimeMillis() / 1000;
        }
        return rtn;
    }

    public static String array2str(List array) {
        if (array == null || array.size() == 0) {
            return null;
        }
        return array2str(array, ",");
    }

    public static String array2str(List array, String splt) {
        if (array == null || array.size() == 0) {
            return null;
        }
        String[] objects = (String[]) array.toArray(new String[array.size()]);
        return array2str(objects, splt);
    }

    /**
     * 数组 转化为字符串
     *
     * @param array
     * @param splt  分隔符,默认逗号(,)
     * @return
     */
    public static String array2str(String[] array, String splt) {
        if (array != null && array.length > 0) {
            if (StringUtils.isBlank(splt)) {
                splt = ",";
            }
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < array.length; i++) {
                if (i > 0) {
                    sb.append(splt);
                }
                sb.append(array[i]);
            }
            return sb.toString();
        } else {
            return null;
        }
    }


    /**
     * 复制list中泛型对象的
     *
     * @param source
     * @param targetClass
     * @return
     * @throws IllegalAccessException
     * @throws InstantiationException
     */
    public static <T> List<T> copyListProperpatternties(List<Object> source, Class<T> targetClass) throws IllegalAccessException, InstantiationException {
        List<T> list = new ArrayList<>();
        if (source != null) {
            for (Object obj : source) {
                T t = targetClass.newInstance();
                BeanUtils.copyProperties(obj, t);
                list.add(t);
            }
        }
        return list;
    }

    /**
     * 将图片写到 硬盘指定目录下
     *
     * @param in
     * @param filePath
     */
    public static void savePicToDisk(InputStream in, String filePath) {

        try {
            File file = new File(filePath);
            if (!file.exists()) {
                file.getParentFile().mkdirs();
                file.createNewFile();
            }

            FileOutputStream fos = new FileOutputStream(file);
            byte[] buf = new byte[1024];
            int len = 0;
            while ((len = in.read(buf)) != -1) {
                fos.write(buf, 0, len);
            }
            fos.flush();
            fos.close();

        } catch (IOException e) {
            log.error("savePicToDisk-fail-1, e: {}", e);
            e.printStackTrace();
        } finally {
            try {
                in.close();
            } catch (IOException e) {
                log.error("savePicToDisk-fail-2, e: {}", e);
                e.printStackTrace();
            }
        }
    }
}
